﻿#include "CRtpSender.h"
#include <string.h>
#include "rtpudpv4transmitter.h"
#include "rtpsessionparams.h"
#include <string>
using namespace std;
using namespace jrtplib;
#pragma warning(disable:4996)
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")

#define SSRC           100

#define DEST_IP_STR   "192.168.0.109"
#define DEST_PORT     2222
#define BASE_PORT     1234

int iNal = 0;
//x264_nal_t* pNals = NULL;

CRtpSender* pSender = NULL;

void SetRTPParams(CRtpSender& sess, uint32_t destip, uint16_t destport, uint16_t baseport)
{
	int status;
	//RTP+RTCP库初始化SOCKET环境
	RTPUDPv4TransmissionParams transparams;
	RTPSessionParams sessparams;
	sessparams.SetOwnTimestampUnit(1.0 / 9000.0); //时间戳单位
#if 0
	sessparams.SetAcceptOwnPackets(true);	//接收自己发送的数据包
	sessparams.SetUsePredefinedSSRC(true);  //设置使用预先定义的SSRC
	sessparams.SetPredefinedSSRC(SSRC);     //定义SSRC
#endif

	transparams.SetPortbase(baseport);

	status = sess.Create(sessparams, &transparams);
	CheckError(status);

#if 1
	destip = ntohl(destip);
	RTPIPv4Address addr(destip, destport);
	status = sess.AddDestination(addr);
	CheckError(status);
#endif

	//为发送H264包设置参数
	//sess.SetParamsForSendingH264();

}

bool InitSocket()
{
	int Error;
	WORD VersionRequested;
	WSADATA WsaData;
	VersionRequested = MAKEWORD(2, 2);
	Error = WSAStartup(VersionRequested, &WsaData); //启动WinSock2
	if (Error != 0)
	{
		printf("Error:Start WinSock failed!\n");
		return false;
	}
	else
	{
		if (LOBYTE(WsaData.wVersion) != 2 || HIBYTE(WsaData.wHighVersion) != 2)
		{
			printf("Error:The version is WinSock2!\n");
			WSACleanup();
			return false;
		}

	}
	return true;
}

void CloseSocket(CRtpSender *sess)
{
	//发送一个BYE包离开会话最多等待秒钟超时则不发送
	sess->BYEDestroy(RTPTime(3, 0), 0, 0);
	WSACleanup();
}

int FindStartCode(unsigned char Buffer[], int nLen, int& nStartCodeLen)
{
	for (int i = 0; i < nLen - 2; i++)
	{
		if (Buffer[i] == 0x00 && Buffer[i + 1] == 0x00)
		{
			if (Buffer[i + 2] == 0x01)
			{
				nStartCodeLen = 3;
				return i;
			}
			else if (Buffer[i + 2] == 0x00 && (Buffer[i + 3] == 0x01 && i + 3 < nLen))
			{
				nStartCodeLen = 4;
				return i;
			}
		}
	}

	return -1;
}
typedef enum __FrameType
{
	VIDEO_FRAME_I = 0x01,
	VIDEO_FRAME_P = 0x02,
	VIDEO_FRAME_B = 0x03,
	VIDEO_FRAME_SEI = 0x04,
	VIDEO_FRAME_SPS = 0x05,
	VIDEO_FRAME_PPS = 0x06,
	AUDIO_FRAME = 0x11,
	UNKNOW = 0x00,
}FrameType;
typedef struct __AVFrame
{
	unsigned char* pBuf;     // frame data
	int nSize;      // frame size
	FrameType eFrameType;   // frame type
	int nTimestamp; // timestamp
	int nStartCodeLen;

	__AVFrame()
	{
		pBuf = NULL;
		nSize = 0;
		eFrameType = UNKNOW;
		nTimestamp = 0;
	}

	__AVFrame(int size)
	{
		pBuf = new unsigned char[size];
		nSize = size;
		eFrameType = UNKNOW;
		nTimestamp = 0;
	}
}AVFrame;

void HandleFileData(unsigned char Buffer[], int nLen, bool bIsEnd)
{
	static AVFrame s_Frame;
	static bool s_bIsStart = false;
	int nStart = 0;
	int nIndex = 0;
	int nSize = 0, nNewSize = 0;
	int nStartCodeLen = 4;
	int nTypeIndex = 0;

	nIndex = FindStartCode(Buffer, nLen, nStartCodeLen);
	//printf("%s: nIndex=%d, s_bIsStart=%d, nStartCodeLen=%d\n", __FILE__, nIndex, s_bIsStart, nStartCodeLen);
	if (nIndex >= 0)
	{
		if (s_bIsStart == true)
		{
			// end or next start
			if (nIndex > 0)
			{
				nSize = s_Frame.nSize;
				nNewSize = s_Frame.nSize + nIndex;
				s_Frame.pBuf = (unsigned char*)realloc(s_Frame.pBuf, nNewSize * sizeof(unsigned char));
				memcpy(&s_Frame.pBuf[nSize], Buffer, nIndex);
				s_Frame.nSize = nNewSize;
			}
			// copy
#if ADD_START_CODE_TO_FRAME == 1
			nTypeIndex = s_Frame.nStartCodeLen;
#else
			nTypeIndex = 0;
#endif
			//s_Frame.eFrameType = GetFrameType(s_Frame.pBuf[nTypeIndex] & 0x1F);

			pSender->SendH264Nalu(s_Frame.pBuf, s_Frame.nSize);
			RTPTime::Wait(RTPTime(0, 30));

			free(s_Frame.pBuf);
			s_Frame.pBuf = NULL;
			s_Frame.nSize = 0;

			s_Frame.nStartCodeLen = nStartCodeLen;
#if ADD_START_CODE_TO_FRAME == 1
			s_Frame.pBuf = (unsigned char*)malloc(nStartCodeLen * sizeof(unsigned char));
			s_Frame.nSize = nStartCodeLen;
			memcpy(&s_Frame.pBuf[0], &Buffer[nIndex], nStartCodeLen);
#endif
			HandleFileData(&Buffer[nIndex + nStartCodeLen], nLen - nIndex - nStartCodeLen, bIsEnd);
		}
		else {
			s_bIsStart = true;
			// start
			s_Frame.nStartCodeLen = nStartCodeLen;
#if ADD_START_CODE_TO_FRAME == 1
			s_Frame.pBuf = (unsigned char*)malloc(nStartCodeLen * sizeof(unsigned char));
			s_Frame.nSize = nStartCodeLen;
			memcpy(&s_Frame.pBuf[0], &Buffer[nIndex], nStartCodeLen);
#endif
			HandleFileData(&Buffer[0 + nStartCodeLen], nLen - nStartCodeLen, bIsEnd);
		}
	}
	else {
		if (s_bIsStart == true)
		{
			// 中间数据
			nSize = s_Frame.nSize;
			nNewSize = s_Frame.nSize + nLen;
			s_Frame.pBuf = (unsigned char*)realloc(s_Frame.pBuf, nNewSize * sizeof(char));
			memcpy(&s_Frame.pBuf[nSize], Buffer, nLen);
			s_Frame.nSize = nNewSize;
		}
		else {
			// error data
		}
	}
}

#define MAX_FILE_BUFFER_LEN      1024
void sendFile(string path)
{
	FILE* pf = fopen(path.c_str(), "rb");
	if (pf == NULL)
		return;

	static unsigned char Buffer[MAX_FILE_BUFFER_LEN] = { 0 };
	int nLen = 0;
	while (true) {
		nLen = fread(Buffer, 1, MAX_FILE_BUFFER_LEN, pf);
		if (feof(pf)) {
			HandleFileData(Buffer, nLen, true);
			printf("restart\n");
			//break;
			fseek(pf, 0, SEEK_SET);
		} else {
			HandleFileData(Buffer, nLen, false);
		}

		RTPTime::Wait(RTPTime(0, 30));
	}

	fclose(pf);
}


int main11(int argc, char** argv)
{
	InitSocket();
	CRtpSender sender;
	string destip_str = "127.0.0.1";
	uint32_t dest_ip = inet_addr(destip_str.c_str());

	SetRTPParams(sender, dest_ip, DEST_PORT, BASE_PORT);
	sender.SetParamsForSendingH264();

	pSender = &sender;
	sendFile("test.h264");
	while (1);

#if 0
	//…x264设置参数等步骤，具体参见上篇博客
	for (int i = 0; i < nFrames; i++)
	{
		//读取一帧
		read_frame_y4m(pPicIn, (hnd_t*)y4m_hnd, i);
		if (i == 0)
			pPicIn->i_pts = i;
		else
			pPicIn->i_pts = i - 1;

		//编码
		int frame_size = x264_encoder_encode(pX264Handle, &pNals, &iNal, pPicIn, pPicOut);

		if (frame_size > 0)
		{

			for (int i = 0; i < iNal; ++i)
			{//将编码数据写入文件t
				//fwrite(pNals[i].p_payload, 1, pNals[i].i_payload, pFile);
				//发送编码文件
				sender.SendH264Nalu(pNals[i].p_payload, pNals[i].i_payload);
				RTPTime::Wait(RTPTime(1, 0));
			}
		}
	}
#endif

	CloseSocket(&sender);
	//一些清理工作…
}